#include "TransformableActor.h"
#include "scene.h"
#include "transform.h"
#include "transformable.h"
#include "vectorproperties.h"
#include "matrixcom.h"
#include "datamanager.h"
#include "numberproperty.h"
#include "stringproperty.h"

namespace VrDataCore
{
	TransformableActor::TransformableActor():_defaultPublicStateSet(NULL)
	{
		setClassName(CLASS_TRANSFORMABLE);
		_notDefaultStateSet = new osg::StateSet;
		_currentStateSet = DEFAULT_STATESET;
	}

	void TransformableActor::buildPropertyMap()
	{
		//AddProperty(new BooleanActorProperty(PROPERTY_NORMAL_RESCALING, PROPERTY_NORMAL_RESCALING,
		//         BooleanActorProperty::SetFuncType(trans, &CoreBase::Transformable::SetNormalRescaling),
		//         BooleanActorProperty::GetFuncType(trans, &CoreBase::Transformable::GetNormalRescaling),
		//         "Enables the automatic scaling of normals when a CoreBase::Transformable is scaled",
		//         GROUPNAME));
		////COLLISION PROPS...
		addProperty(new UIntProperty<TransformableActor>(XML_ELEMENT_DATATYPE_UINT,
			ACTOR_PROPERYT_TRAVERSEMASK,"",this,&TransformableActor::setInitialTraverseMask,
			&TransformableActor::getInitialTraverseMask,"",""));

		//AddProperty(new BooleanActorProperty("Show Collision Geometry", "ODE Show Collision Geometry",  
		//         BooleanActorProperty::SetFuncType(this, &TransformableActor::SetRenderCollisionGeometry),
		//         BooleanActorProperty::GetFuncType(this, &TransformableActor::GetRenderCollisionGeometry),
		//         "Enables/Disables the rendering of collision geometry assigned to this actor (using ODE).",
		//         COLLISION_GROUP));
		//AddProperty(new EnumActorProperty<CoreBase::Transformable::CollisionGeomType>(
		//         PROPERTY_COLLISION_TYPE,"ODE Collision Type",
		//         EnumActorProperty<CoreBase::Transformable::CollisionGeomType>::SetFuncType(this,&TransformableActor::SetCollisionType),
		//         EnumActorProperty<CoreBase::Transformable::CollisionGeomType>::GetFuncType(this,&TransformableActor::GetCollisionType),
		//         "Sets the type of geometry to use for collision detection (using ODE)",
		//         COLLISION_GROUP));
		//AddProperty(new FloatActorProperty(PROPERTY_COLLISION_RADIUS,"ODE Collision Radius",
		//         FloatActorProperty::SetFuncType(this, &TransformableActor::SetCollisionRadius),
		//         FloatActorProperty::GetFuncType(this, &TransformableActor::GetCollisionRadius),
		//         "Sets the radius for collision calculations (using ODE). This value is used differently "
		//         "depending on the type of collision assigned to this actor.  For example, "
		//         "if the collision type is set to SPHERE, this will be the sphere's radius.",
		//         COLLISION_GROUP));
		//AddProperty(new FloatActorProperty(PROPERTY_COLLISION_LENGTH,"ODE Collision Length",
		//         FloatActorProperty::SetFuncType(this, &TransformableActor::SetCollisionLength),
		//         FloatActorProperty::GetFuncType(this, &TransformableActor::GetCollisionLength),
		//         "Sets the length of the collision geometry (using ODE). This value is used differently "
		//         "depending on the type of collision assigned to this actor.  For example, "
		//         "if the collision type is set to CYLINDER, this will be the cylinder's length.",
		//         COLLISION_GROUP));
		//AddProperty(new Vec3Property(PROPERTY_COLLISION_BOX,"ODE Collision Box",
		//         Vec3Property::SetFuncType(this, &TransformableActor::SetCollisionBoxDims),
		//         Vec3Property::GetFuncType(this, &TransformableActor::GetCollisionBoxDims),
		//         "Sets the size of the bounding box used for collision detection (using ODE).  This property "
		//         "is used if the collision type is set to BOX.",
		//         COLLISION_GROUP));
		//AddProperty(new BooleanActorProperty(PROPERTY_ENABLE_COLLISION, "ODE Collision Enable",
		//         BooleanActorProperty::SetFuncType(trans, &CoreBase::Transformable::SetCollisionDetection),
		//         BooleanActorProperty::GetFuncType(trans, &CoreBase::Transformable::GetCollisionDetection),
		//         "Enables collision detection on this actor (using ODE).",
		//         COLLISION_GROUP));
	}

	void TransformableActor::setTraverseMask(unsigned int mask)
	{
		static_cast<CoreBase::Transformable*>(getDrawable())->setTraverseMask(mask);
	}

	unsigned int TransformableActor::getTrasverseMask()
	{
		return static_cast<CoreBase::Transformable*>(getDrawable())->getTraverseMask();
	}

	void TransformableActor::setInitialTraverseMask(unsigned int mask)
	{
		static_cast<CoreBase::Transformable*>(getDrawable())->setInitialTraverseMask(mask);
	}

	unsigned int TransformableActor::getInitialTraverseMask()
	{
		return static_cast<CoreBase::Transformable*>(getDrawable())->getInitialTraverseMask();
	}

	void TransformableActor::setRotation(osg::Vec3 rotation)
	{
		CoreBase::Transformable *t = static_cast<CoreBase::Transformable*>(getDrawable());
		osg::Vec3 hpr = rotation;
		if (hpr.x() < 0.0f)
			hpr.x() += 360.0f;
		if (hpr.x() > 360.0f)
			hpr.x() -= 360.0f;
		if (hpr.y() < 0.0f)
			hpr.y() += 360.0f;
		if (hpr.y() > 360.0f)
			hpr.y() -= 360.0f;
		if (hpr.z() < 0.0f)
			hpr.z() += 360.0f;
		if (hpr.z() > 360.0f)
			hpr.z() -= 360.0f;
		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 oldValue;
		trans.getRotation(oldValue);
		trans.setRotation(osg::Vec3(hpr[2],hpr[0],hpr[1]));
		t->setTransform(trans, CoreBase::Transformable::REL_CS);
		onRotation(osg::Vec3(oldValue[1], oldValue[2], oldValue[0]), hpr);
	}

	void TransformableActor::setRotationFromMatrix(const osg::Matrix &rotation)
	{
		osg::Vec3 hpr;
		CoreBase::MatrixCom::matrixToHpr(hpr,rotation);
		setRotation(osg::Vec3(hpr[1],hpr[2],hpr[0]));
	}

	osg::Vec3 TransformableActor::getRotation()
	{
		const CoreBase::Transformable *t = static_cast<const CoreBase::Transformable*>(getDrawable());
		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 hpr;
		trans.getRotation(hpr);
		return osg::Vec3(hpr[1],hpr[2],hpr[0]);
	}

	void TransformableActor::setTranslation(osg::Vec3 translation)
	{
		CoreBase::Transformable *t = static_cast<CoreBase::Transformable*>(getDrawable());

		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 oldTrans;
		trans.getTranslation(oldTrans);
		trans.setTranslation(translation[0], translation[1], translation[2]);
		t->setTransform(trans, CoreBase::Transformable::REL_CS);
		onTranslation(oldTrans, translation);
	}

	void TransformableActor::setScale(osg::Vec3 scale)
	{
		CoreBase::Transformable *t = static_cast<CoreBase::Transformable*>(getDrawable());
		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 oldValue;
		trans.calcScale(oldValue);
		trans.rescale(scale);
		trans.calcScale(oldValue);
		t->setTransform(trans, CoreBase::Transformable::REL_CS);
	}

	osg::Vec3 TransformableActor::getScale()
	{
		const CoreBase::Transformable *t = static_cast<const CoreBase::Transformable*>(getDrawable());
		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 scale;
		trans.calcScale(scale);
		return scale;
	}

	osg::Vec3  TransformableActor::getTranslation()
	{
		const CoreBase::Transformable *t = static_cast<const CoreBase::Transformable*>(getDrawable());

		CoreBase::Transform trans;
		t->getTransform(trans, CoreBase::Transformable::REL_CS);
		osg::Vec3 result;
		trans.getTranslation(result);
		return result;
	}

	void TransformableActor::setUseDefaultStateSet(bool def)
	{
		_previousStateSet = _currentStateSet;
		if(def)
			_currentStateSet = DEFAULT_STATESET;
		else
			_currentStateSet = NODEFAULT_STATESET;
	}

	void TransformableActor::setUseSpecialStateSet(const QString& tag,bool enable)
	{
		if(enable)
		{
			_previousStateSet = _currentStateSet;
			_currentStateSet = SPECIAL_STATESET;
			_specialPublicStateSet = VrDataCore::DataManager::GetInstance().getPublicStateSetByDrawableName(tag).get();
		}
		else
			_currentStateSet = _previousStateSet;
	}

	void TransformableActor::setDefaultStateSet(osg::StateSet* ss)
	{
		_defaultPublicStateSet = ss;
	}

	void TransformableActor::useStateSet(bool use)
	{
		if(use)
		{
			switch(_currentStateSet)
			{
			case DEFAULT_STATESET:
				//if(_defaultPublicStateSet == NULL)
				//	_defaultPublicStateSet = VrDataCore::DataManager::GetInstance().getPublicStateSetByDrawableName(getName()).get();
				getDrawable()->getOSGNode()->setStateSet(_defaultPublicStateSet);
				break;
			case NODEFAULT_STATESET:
				getDrawable()->getOSGNode()->setStateSet(_notDefaultStateSet.get());
				break;
			case SPECIAL_STATESET:
				getDrawable()->getOSGNode()->setStateSet(_specialPublicStateSet);
				break;
			default:
				break;
			}
		}
		else
		{
			getDrawable()->getOSGNode()->setStateSet(NULL);
		}
	}

	CoreBase::ActorFactory* TransformableActor::getActorFactory()
	{
		 return VrDataCore::DataManager::GetInstance().getActorFactory();
	}

	void TransformableActor::addChild(CoreBase::ActorBase* mactor)
	{
		if(mactor->getDrawable()!=NULL)
			getDrawable()->addChild(mactor->getDrawable());
		if(getBelongMap()!=NULL)
			getBelongMap()->addActor(*mactor);
	}

	void TransformableActor::removeChild(CoreBase::ActorBase* mactor)
	{
		if(mactor==NULL || mactor->getDrawable()==NULL)
			return;
		getDrawable()->removeChild(mactor->getDrawable());
		if(getBelongMap())
			getBelongMap()->removeActor(*mactor);
	}

	void TransformableActor::setToDefaultStateSet()
	{
		setUseDefaultStateSet(true);
		useStateSet();
	}

	/*void TransformableActor::setRenderCollisionGeometry(bool enable)
	{
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());

	phys->RenderCollisionGeometry(enable);
	}

	bool TransformableActor::GetRenderCollisionGeometry() const
	{
	const CoreBase::Transformable *phys = static_cast<const CoreBase::Transformable*>(getDrawable());

	return phys->GetRenderCollisionGeometry();
	}

	void TransformableActor::SetCollisionType(CoreBase::Transformable::CollisionGeomType &type)
	{
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());

	mCollisionType = &type;
	if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::NONE)
	phys->ClearCollisionGeometry();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::CUBE)
	SetBoxCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::SPHERE)
	SetSphereCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::CYLINDER)
	SetCylinderCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::RAY)
	SetRayCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::MESH)
	SetMeshCollision();
	}

	CoreBase::Transformable::CollisionGeomType &TransformableActor::GetCollisionType()
	{
	return *mCollisionType;
	}

	void TransformableActor::SetCollisionRadius(float radius)
	{
	mCollisionRadius = radius;
	if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::CYLINDER)
	SetCylinderCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::SPHERE)
	SetSphereCollision();
	}

	float TransformableActor::GetCollisionRadius() const
	{
	return mCollisionRadius;
	}

	void TransformableActor::SetCollisionBoxDims(const osg::Vec3 &dims)
	{
	mCollisionBoxDims = dims;
	SetBoxCollision();
	}

	osg::Vec3 TransformableActor::GetCollisionBoxDims() const
	{
	return mCollisionBoxDims;
	}

	void TransformableActor::SetCollisionLength(float length)
	{
	mCollisionLength = length;
	if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::CYLINDER)
	SetCylinderCollision();
	else if (mCollisionType == &CoreBase::Transformable::CollisionGeomType::RAY)
	SetRayCollision();
	}

	float TransformableActor::GetCollisionLength() const
	{
	return mCollisionLength;
	}

	void TransformableActor::SetBoxCollision()
	{
	if (mCollisionType != &CoreBase::Transformable::CollisionGeomType::CUBE)
	return;
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());
	phys->ClearCollisionGeometry();
	if (mCollisionBoxDims.x() == 0.0f || mCollisionBoxDims.y() == 0.0f ||
	mCollisionBoxDims.z() == 0.0f)
	{
	phys->SetCollisionBox(NULL);
	}
	else
	{
	phys->SetCollisionBox(mCollisionBoxDims.x(),mCollisionBoxDims.y(),
	mCollisionBoxDims.z());
	}
	}

	void TransformableActor::SetSphereCollision()
	{
	if (mCollisionType != &CoreBase::Transformable::CollisionGeomType::SPHERE)
	return;
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());
	phys->ClearCollisionGeometry();
	if (mCollisionRadius == 0.0f)
	phys->SetCollisionSphere((osg::Node *)NULL);
	else
	phys->SetCollisionSphere(mCollisionRadius);
	}

	void TransformableActor::SetCylinderCollision()
	{
	if (mCollisionType != &CoreBase::Transformable::CollisionGeomType::CYLINDER)
	return;
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());
	phys->ClearCollisionGeometry();
	if (mCollisionRadius == 0.0f || mCollisionLength == 0.0f)
	phys->SetCollisionCappedCylinder(NULL);
	else
	phys->SetCollisionCappedCylinder(mCollisionRadius,mCollisionLength);
	}

	void TransformableActor::SetRayCollision()
	{
	if (mCollisionType != &CoreBase::Transformable::CollisionGeomType::RAY)
	return;
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());
	phys->ClearCollisionGeometry();
	phys->SetCollisionRay(mCollisionLength);
	}

	void TransformableActor::SetMeshCollision()
	{
	if (mCollisionType != &CoreBase::Transformable::CollisionGeomType::MESH)
	return;
	CoreBase::Transformable *phys = static_cast<CoreBase::Transformable*>(getDrawable());
	phys->ClearCollisionGeometry();
	phys->SetCollisionMesh(NULL);
	}*/
}